package com.samsungmobile.common_module;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang.StringUtils;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.samsungmobile.common.Conf;
import com.samsungmobile.common.ConfOta;
import com.samsungmobile.common.channel.ServletManager;
import com.samsungmobile.common.db.value.StringValue;
import com.samsungmobile.common.util.EasyString;
import com.samsungmobile.common_module.Bean.SendMTMResult;
import com.samsungmobile.common_module.Bean.TrackItem;
import com.samsungmobile.common_module.Exception.CommonModuleException;
import com.samsungmobile.common_module.Parser.ResponseData;
import com.samsungmobile.common_module.Parser.SendMTMResultParser;
import com.samsungmobile.common_module.Parser.TrackResponseParser;
import com.samsungmobile.security.UKDESEncryptDecrypt;

public class ReceiveIpxMo_ContentId extends ServletManager {

	// Parameter Values
	private String spDestinationAddress = "";
	private String spOriginatorAddress = "";
	private String spMessage = "";
	private String spMessageId = "";
	private String spTimeStamp = "";
	private String spOperator = "";
	private String sCountryCode = "";

	private final String[] safSUCCESS = { "0", "SUCCESS" };
	private final String[] safINVALID_DESTINATION_ADDRESS = { "401",
			"INVALID_DESTINATION_ADDRESS" };
	private final String[] safINVALID_ORIGINATOR_ADDRESS = { "402",
			"INVALID_ORIGINATOR_ADDRESS" };
	private final String[] safINVALID_MESSAGE_LENGTH = { "403",
			"INVALID_MESSAGE_LENGTH" };
	private final String[] safINVALID_MESSAGE_ID_LENGTH = { "404",
			"INVALID_MESSAGE_ID_LENGTH" };
	private final String[] safINVALID_TIMESTAMP_LENGTH = { "405",
			"INVALID_TIMESTAMP_LENGTH" };
	private final String[] safINVALID_TIMESTAMP = { "406", "INVALID_TIMESTAMP" };
	private final String[] safINVALID_OPERATOR = { "407", "INVALID_OPERATOR" };
	private final String[] safAPI_INTERNAL_ERROR = { "500",
			"API_INTERNAL_ERROR" };
	// Technical problems with service provider:
	private final String sfSERVICE_ERROR = "400";

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.samsungmobile.common.channel.ServletManager#process()
	 */
	protected void process() throws Exception {

		HashMap<String, String> hm = new HashMap<String, String>();
		PrintWriter out = res.getWriter();

		try {
			res.setContentType("text/xml; charset=UTF-8");

			setParams(req);
			checkValidation();

			String sContentId = getOrderContentId();

			TrackItem trackItem = getContentDetail(sContentId);

			if (trackItem != null) {
				
				SendMTMResult result = sendWapPush(trackItem.getWapPushURL(),
						trackItem.getTitle());

				StringBuffer sbQuery = new StringBuffer();
				Vector vParam = new Vector();

				insertMoReceived(sbQuery, vParam, result);

				if (!updateQuery(sbQuery.toString(), vParam))
					throw new CommonModuleException(safAPI_INTERNAL_ERROR);

				if (result.getResponseCode() != 0) { // if not success send
														// wappush
					throw new CommonModuleException(new String[] {
							sfSERVICE_ERROR, result.getResponseMessage() });
				}

			} else {
				insertMoMissed();

			}

			hm.put("RESULT_ACK", "true");
			hm.put("RESULT_ACK_CODE", safSUCCESS[0]);
			hm.put("RESULT_ACK_MESSAGE", safSUCCESS[1]);

		} catch (CommonModuleException e) {

			hm.put("RESULT_ACK", "false");
			hm.put("RESULT_ACK_CODE", e.getMessages()[0]);
			hm.put("RESULT_ACK_MESSAGE", e.getMessages()[1]);

		} catch (Exception e) {
			hm.put("RESULT_ACK", "false");
			hm.put("RESULT_ACK_CODE", safAPI_INTERNAL_ERROR[0]);
			hm.put("RESULT_ACK_MESSAGE", safAPI_INTERNAL_ERROR[1]);
			e.printStackTrace();

		} finally {
			responseReturnXml(out, hm);

		}

	}

	/**
	 * @param sbQuery
	 * @param vParam
	 * @param result
	 * @param sSeq
	 * @param sLogNo
	 * @throws Exception
	 */
	private void insertMoReceived(StringBuffer sbQuery, Vector<Object> vParam,
			SendMTMResult result) throws Exception {

		sbQuery.append("INSERT INTO G_IPX_MO		\n");
		sbQuery.append("(DESTINATIONADDRESS    \n");
		sbQuery.append(", ORIGINATORADDRESS    \n");
		sbQuery.append(", MSISDN    \n");
		sbQuery.append(", CONTENT_ID    \n");
		sbQuery.append(", MESSAGE 					    \n");
		sbQuery.append(", MO_MESSAGEID			    \n");
		sbQuery.append(", TIMESTAMP 				    \n");
		sbQuery.append(", OPERATOR 					  \n");
		sbQuery.append(", SEND             	  \n");
		sbQuery.append(", MODIFIED         	  \n");
		sbQuery.append(", MESSAGEID        	  \n");
		sbQuery.append(", RESPONSECODE     	  \n");
		sbQuery.append(", RESPONSEMESSAGE  	  \n");
		sbQuery.append(", SEQ                  \n");
		sbQuery.append(")                      \n");
		sbQuery.append("Values (               \n");
		sbQuery.append(":DestinationAddress    \n");
		vParam.add(new StringValue(spDestinationAddress));
		sbQuery.append(", :OriginatorAddress   \n");
		vParam.add(new StringValue(spOriginatorAddress));
		sbQuery.append(", :Msisdn   \n");
		vParam.add(new StringValue(spOriginatorAddress));
		sbQuery.append(", :ContentId   \n");
		vParam.add(new StringValue(getOrderContentId()));
		sbQuery.append(", :Message             \n");
		vParam.add(new StringValue(spMessage));
		sbQuery.append(", :MessageId           \n");
		vParam.add(new StringValue(spMessageId));
		sbQuery.append(", :TimeStamp           \n");
		vParam.add(new StringValue(spTimeStamp));
		sbQuery.append(", :Operator            \n");
		vParam.add(new StringValue(spOperator));
		sbQuery.append(", :sGubn               \n");
		vParam.add(new StringValue(result.getResponseCode() == 0 ? "S" : "F"));
		sbQuery.append(", SYSDATE              \n");
		sbQuery.append(", :messageid           \n");
		vParam.add(new StringValue(result.getMessageId()));
		sbQuery.append(", :responsecode        \n");
		vParam.add(new StringValue(String.valueOf(result.getResponseCode())));
		sbQuery.append(", :responseMsg         \n");
		vParam.add(new StringValue(result.getResponseMessage()));
		sbQuery.append(", G_IPX_MO_SEQ.nextval \n");
		sbQuery.append(")                      \n");
	
	}

	/**
	 * @throws Exception
	 */
	private void insertMoMissed() throws Exception {

		StringBuffer sbQuery = new StringBuffer();
		Vector<Object> vParam = new Vector<Object>();

		sbQuery.append("INSERT INTO G_IPX_MO_MISSED\n");
		sbQuery
				.append("( SEQ, DESTINATIONADDRESS, ORIGINATORADDRESS, MESSAGE, MESSAGEID, TIMESTAMP, OPERATOR)\n");
		sbQuery
				.append("VALUES( G_IPX_MO_MISSED_SEQ.NEXTVAL , :DestinationAddress, :OriginatorAddress, :Message, :MessageId, :TimeStamp, :Operator)\n");

		vParam.add(new StringValue(spDestinationAddress));
		vParam.add(new StringValue(spOriginatorAddress));
		vParam.add(new StringValue(spMessage));
		vParam.add(new StringValue(spMessageId));
		vParam.add(new StringValue(spTimeStamp));
		vParam.add(new StringValue(spOperator));

		if (!updateQuery(sbQuery.toString(), vParam))
			throw new CommonModuleException(safAPI_INTERNAL_ERROR);
	}

	private String getOrderContentId() {

		String sRtn = "";

		sRtn = spMessage.replaceAll("\\s", "");
		sRtn = spMessage.replaceAll("(?i)(ft)", "");

		return sRtn;
	}

	/**
	 * @return
	 */
	/*
	 * private Vector<Properties> getOrderContent(){
	 * 
	 * StringBuffer sbQuery = new StringBuffer(); Vector<Object> vParam = new
	 * Vector<Object>();
	 * 
	 * sbQuery.append("SELECT   a.seq, a.content_id		  \n");
	 * sbQuery.append("    FROM g_ipx_mo a                   \n");
	 * sbQuery.append("   WHERE a.msisdn = :OriginatorAddress\n");
	 * vParam.add(new StringValue(spOriginatorAddress));
	 * sbQuery.append("     AND a.created >= (SYSDATE - 1)   \n");
	 * sbQuery.append("     AND a.send = 'E'                 \n");
	 * sbQuery.append("     AND rownum = 1                   \n");
	 * sbQuery.append("ORDER BY seq DESC                     \n");
	 * 
	 * Vector<Properties> vRtn = selectQuery(sbQuery.toString(), vParam);
	 * 
	 * return vRtn; }
	 */

	/**
	 * @param sURL
	 * @param sMessage
	 * @return
	 * @throws Exception
	 */
	private SendMTMResult sendWapPush(String sURL, String sMessage)
			throws Exception {

		SendMTMResult result = null;

		// generate the security key for API authorization ("yyyyMM" +
		// dest_address)
		UKDESEncryptDecrypt ukdes = new UKDESEncryptDecrypt();
		SimpleDateFormat sdfmt = new SimpleDateFormat();
		sdfmt.applyPattern("yyyyMM");
		String sec_key = ukdes.encrypt(sdfmt.format(new Date())
				+ spOriginatorAddress);

		// set the request parameters for the SendMTM API call
		HashMap<String, String> reqList = new HashMap<String, String>();
		reqList.put("dest_address", spOriginatorAddress);
		reqList.put("message_type", "wappush");
		reqList.put("message", StringUtils.defaultIfEmpty(sMessage, "Samsung"));
		reqList.put("url", sURL);
		reqList.put("source_address", spDestinationAddress);
		reqList.put("operator", spOperator);
		reqList.put("sec_key", sec_key);

		// use SendMTMService
		return sendMTM(reqList);
	}

	/**
	 * @param sURL
	 * @param sMessage
	 * @return
	 * @throws Exception
	 */
	private TrackItem getContentDetail(String sContentId) throws Exception {

		TrackItem result = null;

		try {
			
			// Send request and get the response
			result = this.parseTrackResponse(this.getUrlConnToStr("http://cs.samsungmobile.co.uk:8080/API/music?fetchType=track&contentId="+ sContentId));
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return result;

	}

	/**
	 * Sends a request to the SendMTM API, receive and parses the response and
	 * returns the result
	 * 
	 * @param paramList
	 * @return
	 * @throws IOException
	 */
	public SendMTMResult sendMTM(Map<String, String> paramList)
			throws IOException {

		SendMTMResult result = null;
		String urlParams = this.setupRequestParams(paramList);

		try {
			// Send request and get the response
			result = this.parseMTMResponse(
					this.getUrlConnToStr((String) Conf.getConf("url_root")+ "servlet_channel?class=common_module.SendMTM",urlParams)
					);
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return result;
	}

	/**
	 * @param sURL
	 * @return
	 * @throws Exception
	 */
	private String getUrlConnToStr(String sURL) throws Exception {

		return getUrlConnToStr(sURL, "");
	}

	/**
	 * Opens the HttpURLConnection and receives and parses the response
	 * 
	 * @param sURL
	 * @param urlParams
	 * @return
	 * @throws IOException
	 */
	private String getUrlConnToStr(String sURL, String urlParams)
			throws IOException {
		HttpURLConnection connection = null;
		String str = null;
		StringBuffer sbReturn = new StringBuffer();

		URL url = new URL(sURL);

		try {
			connection = (HttpURLConnection) url.openConnection();
			connection.setConnectTimeout(2000);
			connection.setReadTimeout(20000);

			connection.setRequestMethod("POST");
			connection.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");

			connection.setRequestProperty("Content-Length", ""
					+ Integer.toString(urlParams.getBytes().length));
			connection.setRequestProperty("Content-Language", "de-DE");

			connection.setUseCaches(false);
			connection.setDoInput(true);
			connection.setDoOutput(true);

			DataOutputStream wr = new DataOutputStream(connection
					.getOutputStream());
			wr.writeBytes(urlParams);
			wr.flush();
			wr.close();

			// result = this.processResponse(connection.getInputStream());
			
			BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
			
			while ((str = br.readLine()) != null) {
				sbReturn.append(str);
			}

		} catch (Exception ex) {
			if (connection != null)
				connection.disconnect();
		} finally {
			if (connection != null)
				connection.disconnect();
		}

		return sbReturn.toString();
	}

	/**
	 * Processes the response content and return the SendMTM result
	 * 
	 * @param responseContent
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 */
	private SendMTMResult parseMTMResponse(String sResponseString)
			throws ParserConfigurationException, SAXException {
		SendMTMResult result = null;
	
		// Parse the response with SAX
		if (sResponseString != null) {
			SendMTMResultParser parser = new SendMTMResultParser();
			parser.setResponseContentString(sResponseString);
			parser.processString();
			result = parser.getSendMTMResult();
		}
		
		return result;
	}
	

	/**
	 * Processes the response content and return the TrackItem result
	 * 
	 * @param responseContent
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 */
	private TrackItem parseTrackResponse(String sResponseString)
			throws ParserConfigurationException, SAXException {
		ResponseData responseData = null;
		TrackItem item = null;

		// Parse the response with SAX
		if (sResponseString != null) {
			TrackResponseParser parser = new TrackResponseParser();
			parser.setResponseContentString(sResponseString);
			parser.processString();
			responseData = parser.getResponseData();
		}

		if (responseData != null && responseData.getItemList() != null) {
			if (responseData.getItemList().size() > 0) {
				item = (TrackItem) responseData.getItemList().get(0);
			}
		} else {
			// log.error("No content found for id '" + contentId + "'");
		}
		return item;
	}

	/**
	 * Setups the request parameters including URL encoding
	 * 
	 * @param paramList
	 * @return String
	 * @throws UnsupportedEncodingException
	 */
	private String setupRequestParams(Map<String, String> paramList)
			throws UnsupportedEncodingException {
		String urlParams = "";

		for (String key : paramList.keySet()) {
			if (paramList.get(key) != null) {
				if (urlParams != "") {
					urlParams += "&";
				}

				urlParams += key.toString() + "="
						+ URLEncoder.encode(paramList.get(key), "UTF-8");
			}
		}
		// Logger.LOG_OTA.info("SendMTMServiceImpl: request params: "+urlParams);
		System.out.println("SendMTMServiceImpl: request params: " + urlParams);
		return urlParams;
	}

	/**
	 * @param request
	 * @throws CommonModuleException
	 */
	private void setParams(HttpServletRequest request)
			throws CommonModuleException {

		spDestinationAddress = EasyString.toString(
				request.getParameter("DestinationAddress")).trim();
		spOriginatorAddress = EasyString.toString(
				request.getParameter("OriginatorAddress")).trim();
		spMessage = EasyString.toString(request.getParameter("Message")).trim();
		spMessageId = EasyString.toString(request.getParameter("MessageId"))
				.trim();
		spTimeStamp = EasyString.toString(request.getParameter("TimeStamp"))
				.trim();
		spOperator = EasyString.toString(request.getParameter("Operator"))
				.trim();

		sCountryCode = ConfOta.getConf(getCountry() + ".code");
	}

	/**
	 * @return
	 * @throws CommonModuleException
	 */
	private String getCountry() throws CommonModuleException {

		String[] saCountry = ConfOta.getArray("countries");
		String sCountry = "";

		for (int i = 0; i < saCountry.length; i++) {

			if (spOriginatorAddress.startsWith(saCountry[i])) {
				sCountry = saCountry[i];
				break;
			}
		}

		return sCountry;
	}

	/**
	 * @param out
	 * @param hmResult
	 */
	private void responseReturnXml(PrintWriter out,
			HashMap<String, String> hmResult) {

		String sRes = "<DeliveryResponse ack=\"" + hmResult.get("RESULT_ACK")
				+ "\" ackCode=\"" + hmResult.get("RESULT_ACK_CODE")
				+ "\" ackMessage=\"" + hmResult.get("RESULT_ACK_MESSAGE")
				+ "\" />";
		out.println(sRes);
	}

	/**
	 * @throws Exception
	 */
	private void checkValidation() throws Exception {

		String[] saCountry = ConfOta.getArray("countries");
		String sCountries = StringUtils.join(saCountry, "|");

		if (!spDestinationAddress.matches("^\\d{4,11}$")) {
			throw new CommonModuleException(safINVALID_DESTINATION_ADDRESS);

		} else if (!spOriginatorAddress.matches("^(" + sCountries
				+ ")\\d{9,11}")) {
			throw new CommonModuleException(safINVALID_ORIGINATOR_ADDRESS);

		} else if (spMessage.length() > 280) {
			throw new CommonModuleException(safINVALID_MESSAGE_LENGTH);

		} else if (spMessageId.length() > 22) {
			throw new CommonModuleException(safINVALID_MESSAGE_ID_LENGTH);

		} else if (spTimeStamp.length() > 20) {
			throw new CommonModuleException(safINVALID_TIMESTAMP_LENGTH);

		} else if (spOperator.length() > 100) {
			throw new CommonModuleException(safINVALID_OPERATOR);
		}

		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");

		Date paramDate = (Date) formatter.parse(spTimeStamp);
		Date rightNow = new Date();
		if (paramDate.after(rightNow)) { // if time stamp is later than now
			throw new CommonModuleException(safINVALID_TIMESTAMP);
		}

		if (paramDate.getTime() < rightNow.getTime() - 120 * 60 * 1000) { // if
			// time
			// stamp
			// is
			// older
			// than
			// 120
			// minutes
			throw new CommonModuleException(safINVALID_TIMESTAMP);
		}

	}

	/**
	 * @param b
	 * @param buf
	 */
	private void byte2hex(byte b, StringBuffer buf) {
		char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		int high = ((b & 0xf0) >> 4);
		int low = (b & 0x0f);
		buf.append(hexChars[high]);
		buf.append(hexChars[low]);
	}

	private static String bytesToHex(byte[] data) {
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < data.length; i++) {
			buf.append(byteToHex(data[i]).toUpperCase());
		}
		return (buf.toString());
	}

	private static String byteToHex(byte b) {
		char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'a', 'b', 'c', 'd', 'e', 'f' };
		char array[] = { hexDigit[b >> 4 & 0xf], hexDigit[b & 0xf] };
		return new String(array);
	}

	private static final String hex[] = { "%00", "%01", "%02", "%03", "%04",
			"%05", "%06", "%07", "%08", "%09", "%0a", "%0b", "%0c", "%0d",
			"%0e", "%0f", "%10", "%11", "%12", "%13", "%14", "%15", "%16",
			"%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
			"%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", "%28",
			"%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f", "%30", "%31",
			"%32", "%33", "%34", "%35", "%36", "%37", "%38", "%39", "%3a",
			"%3b", "%3c", "%3d", "%3e", "%3f", "%40", "%41", "%42", "%43",
			"%44", "%45", "%46", "%47", "%48", "%49", "%4a", "%4b", "%4c",
			"%4d", "%4e", "%4f", "%50", "%51", "%52", "%53", "%54", "%55",
			"%56", "%57", "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e",
			"%5f", "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
			"%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f", "%70",
			"%71", "%72", "%73", "%74", "%75", "%76", "%77", "%78", "%79",
			"%7a", "%7b", "%7c", "%7d", "%7e", "%7f", "%80", "%81", "%82",
			"%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8a", "%8b",
			"%8c", "%8d", "%8e", "%8f", "%90", "%91", "%92", "%93", "%94",
			"%95", "%96", "%97", "%98", "%99", "%9a", "%9b", "%9c", "%9d",
			"%9e", "%9f", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6",
			"%a7", "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
			"%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", "%b8",
			"%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", "%c0", "%c1",
			"%c2", "%c3", "%c4", "%c5", "%c6", "%c7", "%c8", "%c9", "%ca",
			"%cb", "%cc", "%cd", "%ce", "%cf", "%d0", "%d1", "%d2", "%d3",
			"%d4", "%d5", "%d6", "%d7", "%d8", "%d9", "%da", "%db", "%dc",
			"%dd", "%de", "%df", "%e0", "%e1", "%e2", "%e3", "%e4", "%e5",
			"%e6", "%e7", "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee",
			"%ef", "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
			"%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" };

}